﻿/* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 Validity Systems Inc.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution, if
*    any, must include the following acknowlegement:
*       "This product includes software developed by the
*        Validity Systems Inc."
*    Alternately, this acknowlegement may appear in the software itself,
*    if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "#Logger", "CS Logger", and "Validity Systems
*    Inc." must not be used to endorse or promote products derived
*    from this software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "#Logger"
*    nor may "#Logger" appear in their names without prior written
*    permission of Validity Systems Inc.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Validity Systems Inc.
*
*
*/

/*
 *  Author: Athony La Forge (Validity Systems Inc.) 
 */

using System;
using System.Collections;
using System.Diagnostics;
using System.Threading;

namespace Calendar.Logic.Log
{



    /// <summary>
    /// Abstract class responsible managing (in the form or a queue) and dispatching log messages
    /// to their appropriate source.  The basic premises is that everything from a file writers, 
    /// to an e-mailer, to an syslog interface, to a db interface, etc... could be implemented and the only
    /// thing the implementer would need to worry about was the interface.
    /// </summary>
    public abstract class LoggerEventHandler
    {
        private bool alive = false;
        protected Queue q = null;
        private Thread dispatch = null;
        protected string[] logLevelDescriptors = null;

        public LoggerEventHandler()
        {
            q = Queue.Synchronized(new Queue(1000));
        }

        /// <summary>
        /// Starts the execution of the Handler (e.g. Queue goes live)
        /// </summary>
        public void start()
        {
            //It's already alive, nothing to do
            if (alive) return;

            //Make sure this is the only place where alive is set to true
            alive = true;
            dispatch = new Thread(new ThreadStart(dispatchMessages));
            dispatch.Start();
        }

        /// <summary>
        /// Stops the execution of the Handler gracefully (e.g. everything in the queue is
        /// dispatched, but nothing can be added to it)
        /// </summary>
        public void shutdown()
        {
            //Nothing to do
            if (!alive) return;

            alive = false;
            try
            {
                if (q != null)
                {
                    Monitor.Enter(q);
                    Monitor.PulseAll(q);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            finally
            {
                if (q != null) Monitor.Exit(q);
            }
        }

        /// <summary>
        /// Will immediately shutdown the thread without cleaning up or clearing
        /// out the queue.  Consequently this is not the recommended way to terminate.
        /// </summary>
        public void abort()
        {
            if (!alive) return;

            alive = false;
            dispatch.Abort();
        }

        /// <summary>
        /// This is the worker method where the messages get dispatched
        /// </summary>
        protected void dispatchMessages()
        {
            //int max = 0;
            while (alive)
            {
                while ((q.Count != 0) && alive)
                {
                    //if(q.Count > max)max = q.Count;
                    log((LoggerMessage)q.Dequeue());
                }

                if ((alive) && (q.Count == 0))
                {
                    try
                    {
                        if (q != null)
                        {
                            Monitor.Enter(q);
                            if (q.Count == 0) Monitor.Wait(q);
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex.Message);
                    }
                    finally
                    {
                        if (q != null) Monitor.Exit(q);
                    }
                }
            }

            //You will only reach this code if you are exiting the program
            //This block ensures the messages that were queued up will get dumped
            while (q.Count != 0)
            {
                log((LoggerMessage)q.Dequeue());
            }

            //Do any special shutdown you need to do
            onShutdown();

            //Remove thread reference so you don't have object leak
            dispatch = null;
        }

        /// <summary>
        /// Responsible for queuing the log message
        /// </summary>
        public void log(DsLogLevel level, string className, string method, string msg, string comm)
        {
            if (!alive) return;

            var lm = new LoggerMessage();
            lm.Level = level;
            lm.Class = className;
            lm.Method = method;
            lm.Msg = msg;
            lm.Comm = comm;
            lm.Time = DateTime.Now;

            try
            {
                if (q != null)
                {
                    Monitor.Enter(q);
                    q.Enqueue(lm);
                    Monitor.PulseAll(q);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            finally
            {
                if (q != null) Monitor.Exit(q);
            }
        }

        protected abstract void log(LoggerMessage message);

        /// <summary>
        /// User implementable, meant for cleanup when the thread is stopped (e.g. if you need to
        /// close files, db connections, etc...)
        /// </summary>
        protected abstract void onShutdown();
    }
}